﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using Tulde.MP3tunes.Model;
using WP7.LockerPlayer.ViewModels;
using Tulde.Core;
using Tulde.MP3tunes;
using Microsoft.Phone.Shell;
using System.Linq;


namespace WP7.LockerPlayer
{
    public enum AppState
    {
        /// <summary>
        /// The application is launched.
        /// </summary>
        Launched,

        /// <summary>
        /// The application is activated after being tombstoned.
        /// </summary>
        Activated,

        /// <summary>
        /// The application is about to be deactivated.
        /// </summary>
        Deactivating,

        /// <summary>
        /// The application is about to be closed.
        /// </summary>
        Closing
    }
    public class MainViewModel : INotifyPropertyChanged
    {
        private static object _synchLock = new object();
        private AppState appState;
        private string[] storageNames = {
                                            "artistsVM",
                                            "albumsVM",
                                            "playlistsVM",
                                            "videosVM",
                                            "mediaPlayerVM"

                                        };


        #region Events
        public event EventHandler DataLoaded;
        #endregion


        #region App Lifecycle Methods
        public void OnApplicationLaunching()
        {
            this.appState = AppState.Launched;

            // we will wait for the loading page to request data load
        }

        public void OnApplicationActivated()
        {
            this.appState = AppState.Activated;

            // upon application re-activating we will load the data synchronously
            this.LoadData();
        }

        public void OnApplicationDeactivated()
        {
            this.appState = AppState.Deactivating;
            this.Save();
            //this.SaveSettings();
        }

        public void OnApplicationClosing(ClosingEventArgs e)
        {
            this.appState = AppState.Closing;
            this.Save();
           // this.SaveSettings();
        }
        private void OnDataLoaded(EventArgs e)
        {
            EventHandler eh = this.DataLoaded;
            if (eh != null)
            {
                eh(this, e);
            }
        }
        #endregion

        [ThreadStatic]
        private static MainViewModel instance;

        public static MainViewModel Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new MainViewModel();
                }
                return instance;
            }
        }



        private LocalizedStrings strings = new LocalizedStrings();
        public const string STORAGE_NAME = "mv.dat";
        public MainViewModel()
        {
            this.Artists = new ObservableCollection<ArtistViewModel>();
            this.Albums = new ObservableCollection<AlbumViewModel>();
            this.Videos = new ObservableCollection<VideoViewModel>();
            this.Playlists = new ObservableCollection<PlaylistViewModel>();
            this.ArtistsGroupedByName = new ObservableCollection<PublicGrouping<string, ArtistViewModel>>();
            this.Artists.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Artists_CollectionChanged);
            this.Albums.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Albums_CollectionChanged);

        }

        void Albums_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            this.BuildGroupAlbumsCollections();
        }

        void Artists_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            this.BuildGroupArtistsCollection();
        }
       

        /// <summary>
        /// A collection of artists
        /// </summary>
        public ObservableCollection<ArtistViewModel> Artists { get; set; }


        public ObservableCollection<PublicGrouping<string, ArtistViewModel>> ArtistsGroupedByName
        {
            get;
            set;
        }
        public ObservableCollection<PublicGrouping<string, AlbumViewModel>> AlbumsGroupedByName
        {
            get;
            set;
        }
        private void BuildGroupArtistsCollection()
        {
            var x = (from artist in this.Artists
                     group artist by ArtistViewModel.GetFirstNameKey(artist)
                         into c
                         orderby c.Key
                         select new PublicGrouping<string, ArtistViewModel>(c)).ToList();

            if (x.Any())
            {

                lock (_synchLock)
                {
                    if (this.ArtistsGroupedByName == null)
                    {
                        this.ArtistsGroupedByName = new ObservableCollection<PublicGrouping<string, ArtistViewModel>>();
                    }
                    this.ArtistsGroupedByName.Clear();
                    foreach (var item in x)
                    {
                        if (item != null)
                        {
                            this.ArtistsGroupedByName.Add(item);
                        }
                    }
                }
            }
        }
        private void BuildGroupAlbumsCollections()
        {
            var x = (from album in this.Albums
                     group album by AlbumViewModel.GetFirstNameKey(album)
                         into c
                         orderby c.Key
                         select new PublicGrouping<string, AlbumViewModel>(c)).ToList();

            if (x.Any())
            {

                lock (_synchLock)
                {
                    if (this.AlbumsGroupedByName == null)
                    {
                        this.AlbumsGroupedByName = new ObservableCollection<PublicGrouping<string, AlbumViewModel>>();
                    }
                    this.AlbumsGroupedByName.Clear();
                    foreach (var item in x)
                    {
                        if (item != null)
                        {
                            this.AlbumsGroupedByName.Add(item);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<AlbumViewModel> Albums { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<PlaylistViewModel> Playlists { get; set; }
        /// <summary>
        /// 
        /// </summary>
        //public ObservableCollection<TrackViewModel> Tracks { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<VideoViewModel> Videos { get; set; }

        private MediaPlayerViewModel _mediaPlayerVM;
        /// <summary>
        /// State data for the MediaPlayer View
        /// </summary>

        public MediaPlayerViewModel MediaPlayer
        {
            get
            {
                if (this._mediaPlayerVM == null)
                {
                    this._mediaPlayerVM = new MediaPlayerViewModel();
                }
                return this._mediaPlayerVM;
            }
            set
            {
                this._mediaPlayerVM = value;
            }
        }
       


        private string _sampleProperty = "Sample Runtime Property Value";
        /// <summary>
        /// Sample ViewModel property; this property is used in the view to display its value using a Binding
        /// </summary>
        /// <returns></returns>
        public string SampleProperty
        {
            get
            {
                return _sampleProperty;
            }
            set
            {
                if (value != _sampleProperty)
                {
                    _sampleProperty = value;
                    NotifyPropertyChanged("SampleProperty");
                }
            }
        }

        public bool IsDataLoaded
        {
            get;
             set;
        }

        private void ExecuteProgress( Action<string> progress, string message)
        {
            if (progress != null)
                progress(message);
          }
        /// <summary>
        /// Creates and adds a few ItemViewModel objects into the Items collection.
        /// </summary>
        public void LoadData(Action<bool> complete=null, Action<Exception> error=null, Action<string> progress = null)
        {
            Tulde.MP3tunes.Mp3TunesMusicService.Authenticate(SecurityProvider.Credentials, callback =>
            {
                SecurityProvider.SetAuthenticationTokens(callback);
                if (this.appState == AppState.Activated)
                {
                    this.ExecuteProgress(progress, "Loading Cache From Storage.");
                    if (StorageProviderFactory.Instance.Exists("artistsVM"))
                    {
                        StorageProviderFactory.Instance.Read<ObservableCollection<ArtistViewModel>>("artistsVM").CopyToObservableCollection(this.Artists);
                    }
                    if (StorageProviderFactory.Instance.Exists("albumsVM"))
                    {
                        StorageProviderFactory.Instance.Read<ObservableCollection<AlbumViewModel>>("albumsVM").CopyToObservableCollection(this.Albums);
                    }
                    if (StorageProviderFactory.Instance.Exists("videosVM"))
                    {
                        StorageProviderFactory.Instance.Read<ObservableCollection<VideoViewModel>>("videosVM").CopyToObservableCollection(this.Videos);
                    }
                    if (StorageProviderFactory.Instance.Exists("playlistsVM"))
                    {
                        StorageProviderFactory.Instance.Read<ObservableCollection<PlaylistViewModel>>("playlistsVM").CopyToObservableCollection(this.Playlists);
                    }
                    //restore view model from Isolated Storage.
                    this.BuildGroupArtistsCollection();
                    this.BuildGroupAlbumsCollections();
                    this.IsDataLoaded = true;
                    if (complete != null)
                    {
                        complete(true);
                    }
                }
                else
                {
                    Mp3TunesMusicService.GetLastUpdate(x =>
                    {

                        this.ExecuteProgress(progress, "Validating Local Cache.");
                        if (ViewModelCacheFactory.Instance.CacheItemExists(Checksum.CACHE_KEY))
                        {
                            Checksum cached = StorageProviderFactory.Instance.Read<Checksum>(Checksum.CACHE_KEY);

                            if (cached.Timestamp != x.Timestamp)
                            {
                                ViewModelCacheFactory.Instance.SetCacheItem<Checksum>(Checksum.CACHE_KEY, x);
                                ViewModelCacheFactory.Instance.Invalidate(MainViewModel.STORAGE_NAME);
                                this.ExecuteProgress(progress, "Refreshing Local Cache.");
                                this.LoadViewModel(complete, error);


                            }
                            else
                            {
                                this.ExecuteProgress(progress, "Loading Cache From Storage.");
                                if (StorageProviderFactory.Instance.Exists("artistsVM"))
                                {
                                    StorageProviderFactory.Instance.Read<ObservableCollection<ArtistViewModel>>("artistsVM").CopyToObservableCollection(this.Artists);
                                }
                                if (StorageProviderFactory.Instance.Exists("albumsVM"))
                                {
                                    StorageProviderFactory.Instance.Read<ObservableCollection<AlbumViewModel>>("albumsVM").CopyToObservableCollection(this.Albums);
                                }
                                if (StorageProviderFactory.Instance.Exists("videosVM"))
                                {
                                    StorageProviderFactory.Instance.Read<ObservableCollection<VideoViewModel>>("videosVM").CopyToObservableCollection(this.Videos);
                                }
                                if (StorageProviderFactory.Instance.Exists("playlistsVM"))
                                {
                                    StorageProviderFactory.Instance.Read<ObservableCollection<PlaylistViewModel>>("playlistsVM").CopyToObservableCollection(this.Playlists);
                                }
                                //restore view model from Isolated Storage.
                                this.BuildGroupArtistsCollection();
                                this.IsDataLoaded = true;
                                if (complete != null)
                                {
                                    complete(true);
                                }

                            }
                        }
                        else
                        {
                            this.ExecuteProgress(progress, "Downloading Locker Data To Local Cache.");
                            StorageProviderFactory.Instance.Save(Checksum.CACHE_KEY, x);
                            //this.statusMessage.Text = "Downloading Locker data.";
                            this.LoadViewModel(complete, error);


                        }
                    });
                }//end last update
            });
            

        }
  
        /// <summary>
        /// Assumes this authentication data has already been cached to isolated storage.
        /// </summary>
        /// <param name="error"></param>
        public void Restore()
        {
            if (StorageProviderFactory.Instance.Exists("mediaPlayerVM") )
            {
                this.MediaPlayer = StorageProviderFactory.Instance.Read<MediaPlayerViewModel>("mediaPlayerVM");
            }
            //what if user didn't save credentials?  This will be null and we will get an expcetion.
            //how do we prompt the user to enter their credentials.
            this.LoadData();
           

        }
        public void Clear()
        {
            foreach( string x in storageNames)
                StorageProviderFactory.Instance.Delete(x);
            StorageProviderFactory.Instance.Delete(Checksum.CACHE_KEY);
        }
        /// <summary>
        /// Downloads all data from MP3tunes and converts into the appropriate view models.
        /// </summary>
        /// <param name="complete"></param>
        /// <param name="error"></param>
        /// 
        private void LoadViewModel( Action<bool> complete, Action<Exception> error)
        {
            PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            
            Mp3TunesMusicService.DownloadLockerData(y =>
            {
                //first attempt to restore the view model from isolated storage.
                ViewModelTranslator.Translate<Artist, ArtistViewModel>(y.Artists, this.Artists, (m, vm) =>
                {
                    vm.AlbumCount = m.AlbumCount;
                    vm.ArtistId = m.ArtistId;
                    vm.ArtistName = m.ArtistName;
                    vm.ArtistSize = m.ArtistSize;
                   
                });
                ViewModelTranslator.Translate<Album, AlbumViewModel>(y.Albums, this.Albums, (m, vm) =>
                {
                    vm.AlbumArtUrl = m.AlbumArtUrl;
                    vm.AlbumId = m.AlbumId;
                    vm.AlbumSize = m.AlbumSize;
                    vm.AlbumTitle = m.AlbumTitle;
                    vm.ArtistId = m.ArtistId;
                    vm.ArtistName = m.ArtistName;
                    vm.HasArt = m.HasArt;
                    vm.TrackCount = m.TrackCount;
                  //  vm.SetTrackCountMessage(m.TrackCount);

                });
                ViewModelTranslator.Translate<Playlist, PlaylistViewModel>(y.Playlists, this.Playlists, (m, vm) =>
                {

                    vm.DateModified = m.DateModified;
                    vm.FileCount = m.FileCount;
                    vm.FileName = m.FileName;
                    vm.PlaylistId = m.PlaylistId;
                    vm.PlayListSize = m.PlayListSize;
                    vm.PlaylistTitle = m.PlaylistTitle;
                    vm.Title = m.Title;
                });
                //set the MainViewModel
                this.IsDataLoaded = true;
                this.Save();
                if (complete != null)
                {
                    complete(true);
                    PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
                }
            }, error);
        }
       
        public void LoadArtistAlbums()
        {

        }
        public void LoadAlbumsTracks(Action<bool> callback,string albumId, string artistId)
        {
            Mp3TunesMusicService.GetAlbumTracks(albumId,artistId, y =>
           {
               //first attempt to restore the view model from isolated storage.
               ViewModelTranslator.Translate<Track, TrackViewModel>(y.Tracks, this.MediaPlayer.CurrentTracks, (m, vm) =>
               {
                   vm.AlbumArtUrl = m.AlbumArtUrl;
                   vm.AlbumId = m.AlbumId;
                   vm.AlbumTitle = m.AlbumTitle;
                   vm.AlbumYear = m.AlbumYear;
                   vm.ArtistName = m.ArtistName;
                   vm.DownloadUrl = m.DownloadUrl;
                   vm.PlaymixURL = m.PlaymixURL;
                   vm.PlayURL = m.PlayURL;
                   vm.TrackFileKey = m.TrackFileKey;
                   vm.TrackFileName = m.TrackFileName;
                   vm.TrackFileSize = m.TrackFileSize;
                   vm.TrackId = m.TrackId;
                   vm.TrackLength = m.TrackLength;
                   vm.TrackNumber = m.TrackNumber;
                   vm.TrackTitle = m.TrackTitle;


               });
               callback(true);
           });
           
        }
        public void LoadPlaylistTracks(Action<bool> callback, string playlistId)
        {
            Mp3TunesMusicService.GetPlaylist(playlistId, y =>
            {
                //first attempt to restore the view model from isolated storage.
                ViewModelTranslator.Translate<Track, TrackViewModel>(y.Tracks, this.MediaPlayer.CurrentTracks, (m, vm) =>
                {
                    vm.AlbumArtUrl = m.AlbumArtUrl;
                    vm.AlbumId = m.AlbumId;
                    vm.AlbumTitle = m.AlbumTitle;
                    vm.AlbumYear = m.AlbumYear;
                    vm.ArtistName = m.ArtistName;
                    vm.DownloadUrl = m.DownloadUrl;
                    vm.PlaymixURL = m.PlaymixURL;
                    vm.PlayURL = m.PlayURL;
                    vm.TrackFileKey = m.TrackFileKey;
                    vm.TrackFileName = m.TrackFileName;
                    vm.TrackFileSize = m.TrackFileSize;
                    vm.TrackId = m.TrackId;
                    vm.TrackLength = m.TrackLength;
                    vm.TrackNumber = m.TrackNumber;
                    vm.TrackTitle = m.TrackTitle;


                });
                callback(true);
            });
        }
        public void Save()
        {
           // StorageProviderFactory.Instance.Save<MainViewModel>(MainViewModel.STORAGE_NAME, this);

            StorageProviderFactory.Instance.Save<ObservableCollection<ArtistViewModel>>("artistsVM", this.Artists);
            StorageProviderFactory.Instance.Save<ObservableCollection<AlbumViewModel>>("albumsVM", this.Albums);
            StorageProviderFactory.Instance.Save<ObservableCollection<VideoViewModel>>("videosVM", this.Videos);
            StorageProviderFactory.Instance.Save<ObservableCollection<PlaylistViewModel>>("playlistsVM", this.Playlists);
            if( this.MediaPlayer != null)
                StorageProviderFactory.Instance.Save<MediaPlayerViewModel>("mediaPlayerVM", this.MediaPlayer);
        }
     
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        

    }
}